package com.tang.lts.core.autoconfigure.resolver;

import com.tang.lts.core.autoconfigure.AutoConfigContext;
import com.tang.lts.core.commons.utils.GenericsUtils;
import com.tang.lts.core.commons.utils.PrimitiveTypeUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author Tang
 * @classname MapResolver
 * @description [  ]
 * @date 2022/4/13 21:42
 */
public class MapResolver extends AbstractResolver {

    public static MapResolver INSTANCE = new MapResolver();

    @Override
    public void resolver(AutoConfigContext autoConfigContext, PropertyDescriptor descriptor, String includeName) {
        Method readMethod = descriptor.getReadMethod();
        Class kClass = GenericsUtils.getMethodGenericReturnType(readMethod, 0);
        Class vClass = GenericsUtils.getMethodGenericReturnType(readMethod, 1);

        // K 必须是原始的类型
        if (!PrimitiveTypeUtils.isPrimitiveType(kClass)) {
            throw new IllegalArgumentException("Only support Map primitive type key");
        }

        Map map = createMap(descriptor.getPropertyType());

        doFilter(autoConfigContext, descriptor, includeName, new Filter() {
            @Override
            public boolean onCondition(String name, String key, String value) {
                return name.contains(key);
            }

            @Override
            public boolean call(String name, String key, String value) {
                writeProperty(autoConfigContext, descriptor, map);
                return false;
            }
        });
    }

    private Map createMap(Class<?> type) {

        if (type == Properties.class) {
            return new Properties();
        }

        if (type == HashMap.class) {
            return new HashMap();
        }

        if (type == ConcurrentMap.class || type == ConcurrentHashMap.class) {
            return new ConcurrentHashMap();
        }

        try {
            return (Map<Object, Object>) type.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}